package com.strongbj.iot.devices.dam;

import java.net.InetSocketAddress;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.strongbj.core.device.Device;
import com.strongbj.core.device.DeviceManager;
import com.strongbj.core.device.IDevice;
import com.strongbj.core.message.MessageHandleContext;
import com.strongbj.iot.devices.dam.common.DAMManager;
import com.strongbj.iot.devices.dam.common.NetMapping;
import com.strongbj.iot.devices.dam.message.DAMMessage;
import com.strongbj.iot.devices.dam.response.handle.v1.DoorStateHandle;
import com.strongbj.iot.devices.dam.response.handle.v1.GetDestServerParamsResultHandle;
import com.strongbj.iot.devices.dam.response.handle.v1.GetNetParamsResultHandle;
import com.strongbj.iot.devices.dam.response.handle.v1.HeartbeatHandle;
import com.strongbj.iot.devices.dam.response.handle.v1.InitCompleteHandle;
import com.strongbj.iot.devices.dam.response.handle.v1.ScreenToServerCommandHandle;
import com.strongbj.iot.devices.dam.response.handle.v1.SetNetParamsResultHandle;
import com.strongbj.iot.devices.dam.response.handle.v1.SetSensorTypeResultHandle;
import com.strongbj.iot.devices.dam.response.handle.v1.TemperatureAndHumidityHandle;
import com.strongbj.iot.devices.dam.sub.dacai.entity.DaCaiBindRFIDMenuManager;
import com.strongbj.iot.devices.dam.sub.dacai.request.handle.RebootNetHandle;
import com.strongbj.iot.devices.dam.sub.dacai.request.handle.ShowSensorParamsReturnHandle;
import com.strongbj.iot.devices.dam.sub.dacai.request.handle.UpdateDaCaiLocalNetPageParams;
import com.strongbj.iot.devices.dam.sub.dacai.request.handle.UpdateDaCaiServerNetPageParams;
import com.strongbj.iot.devices.dam.sub.dacai.request.handle.UpdateDoorStateHandle;
import com.strongbj.iot.devices.dam.sub.dacai.request.handle.UpdateRealtimeSensorDatasHandle;
import com.strongbj.iot.devices.dam.sub.dacai.request.handle.UpdateSensorParamsHandle;
import com.strongbj.iot.devices.dam.sub.dacai.response.handle.DAMToDaCaiScreenHandleContext;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

/**
 * DAM设备响应处理上下文类
 * 
 * @author yuzhantao
 *
 */
public class DAMResponseHandleContext extends SimpleChannelInboundHandler<DAMMessage> {
	/**
	 * 大彩绑定RFID菜单的参数
	 */
	public static final String DACAI_BIND_RFID_MENU_PARAMS = "dacai_bind_rfid_menu_params";
	private static Logger logger = LogManager.getLogger(DAMResponseHandleContext.class.getName());
	// TODO 由于硬件在上报屏幕数据时的设备编号固定写成0000001，顾在心跳的时候记录编号，上报屏幕数据的时候用此编号
	private DAMMessage currentDAM; // 用于记录当前设备的信息
	private MessageHandleContext<DAMMessage, Object> messageHandleContent;

	private Map<String, Object> subDeviceParams = new ConcurrentHashMap<>();

	public void setDeviceParams(String key, Object value) {
		this.subDeviceParams.put(key, value);
	}

	public Object getDeviceParams(String key) {
		return this.subDeviceParams.get(key);
	}

	public void clearAllDeviceParams() {
		this.subDeviceParams.clear();
	}

	public DAMResponseHandleContext() {
		super();
		this.currentDAM = new DAMMessage();
		this.currentDAM.setAddressCode(new byte[3]);

		try {
			this.messageHandleContent = new MessageHandleContext<>(false);
			this.initDAMHandle();
			this.initDaCaiScreen();
		} catch (Exception e) {
			e.printStackTrace();
			logger.error(e);
		}
	}

	/**
	 * 初始化大彩设备
	 */
	protected void initDaCaiScreen() {
		this.messageHandleContent.addHandleClass(new DAMToDaCaiScreenHandleContext(this.currentDAM));
		this.messageHandleContent.addHandleClass(new UpdateDaCaiLocalNetPageParams()); // 更新大彩屏上网络设置界面中的本地网络参数
		this.messageHandleContent.addHandleClass(new UpdateDaCaiServerNetPageParams()); // 更新大彩屏上网络设置界面中的服务器网络参数
		this.messageHandleContent.addHandleClass(new RebootNetHandle());
		this.messageHandleContent.addHandleClass(new UpdateSensorParamsHandle());
		this.messageHandleContent.addHandleClass(new ShowSensorParamsReturnHandle());
		this.messageHandleContent.addHandleClass(new UpdateRealtimeSensorDatasHandle());
		this.messageHandleContent.addHandleClass(new UpdateDoorStateHandle());
	}

	/**
	 * 初始化DAM设备处理类
	 */
	protected void initDAMHandle() {
		this.messageHandleContent.addHandleClass(new TemperatureAndHumidityHandle()); // 温湿度处理类
		this.messageHandleContent.addHandleClass(new HeartbeatHandle(this.currentDAM)); // 心跳处理类
		this.messageHandleContent.addHandleClass(new DoorStateHandle()); // 门状态处理类
		this.messageHandleContent.addHandleClass(new InitCompleteHandle()); // 设备初始化完成处理类

		this.messageHandleContent.addHandleClass(new GetNetParamsResultHandle()); // 获取网卡信息返回的信息成处理类
		this.messageHandleContent.addHandleClass(new SetSensorTypeResultHandle()); // 设置传感器类型后返回的信息成处理类
		this.messageHandleContent.addHandleClass(new GetDestServerParamsResultHandle()); // 获取目标服务器返回的信息成处理类
		this.messageHandleContent.addHandleClass(new ScreenToServerCommandHandle(this.currentDAM)); // 屏幕到服务器命令的处理类
		this.messageHandleContent.addHandleClass(new SetNetParamsResultHandle());// 设置网络发反馈的处理类
	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		logger.info("DAM设备已连接" + ctx.channel().remoteAddress().toString());
		super.channelActive(ctx);
		try {
			NetMapping.getInstance().addChannel(ctx.channel());
		} catch (Exception e) {
			e.printStackTrace();
			logger.error(e);
		}

		try {
			String ip = ((InetSocketAddress) ctx.channel().remoteAddress()).getAddress().getHostAddress();
			Device dev = new Device("", ip);
			DeviceManager.getInstance().registerDevice(dev);
		} catch (Exception e) {
			e.printStackTrace();
			logger.error(e);
		}
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		logger.info("DAM设备已断开" + ctx.channel().remoteAddress().toString());
		super.channelInactive(ctx);
		try {
			NetMapping.getInstance().removeChannel(ctx.channel());
		} catch (Exception e) {
			logger.error("", e);
		}
		try {
			String ip = ((InetSocketAddress) ctx.channel().remoteAddress()).getAddress().getHostAddress();
			IDevice dev = DeviceManager.getInstance().findDevice(ip);
			if (dev != null && dev.getDeviceCode()!=null) {
				try {
					// 移除大彩绑定RFID的菜单数据
					DaCaiBindRFIDMenuManager.getInstance().removeMenu(dev.getDeviceCode());
				} catch (Exception e) {
					logger.error("", e);
				}
				// 清除执行handle发送任务的管理类
				try {
					DAMManager.removeTaskManager(dev.getDeviceCode());
				} catch (Exception e) {
					logger.error("", e);
				}
			}
			DeviceManager.getInstance().unregisterDevice(ip);
		} catch (Exception e) {
			logger.error("", e);
		}

		messageHandleContent.clearHandleClass();
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		super.exceptionCaught(ctx, cause);
		String ip = ((InetSocketAddress) ctx.channel().remoteAddress()).getAddress().getHostAddress();
		logger.error(ip, cause);
		if (ctx.channel().isActive())
			ctx.close();
	}

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, DAMMessage msg) throws Exception {
		if (msg == null)
			return;
		try {
			this.messageHandleContent.handle(ctx, msg);
		} catch (Exception e) {
			logger.error(e);
			e.printStackTrace();
		}
	}
}
